#include "udpServer.hpp"
#include "udpUser.hpp"
#include <iostream>
#include <memory>
#include <cstdlib>
#include <cstring>
#include <unordered_map>
#include <string>
#include <fstream>
#include <signal.h>
#include <cstdio>
#include <strings.h>
using namespace Server;
static void Usage(string proc)
{
    cout << "\nusage: \n\t" << proc << " port\n"
         << endl;
}

// -------------------------demo1:字典 --------------------
string dictTxt = "./dict.txt";
unordered_map<string, string> dict;
// 截取字符串
void cutString(const string buffer, string *s1, string *s2, const string sub)
{
    size_t pos = buffer.find(sub);
    if (pos != string::npos)
    {
        *s1 = buffer.substr(0, pos);
        *s2 = buffer.substr(pos + sub.size());
    }
    else
    {
        // do nothing
    }
}

void debugInit()
{
    for(const auto& e : dict)
    {
        cout << e.first << ":" << e.second << endl;
    }
}
// 初始化字典
void initDict()
{
    ifstream ofs(dictTxt);
    if(!ofs.is_open())
    {
        cerr << "open file fail" << endl;
        exit(FILE_ERR);
    }
    string buffer;
    while (getline(ofs, buffer))
    {
        string key, value;
        cutString(buffer, &key, &value, ":");
        dict[key] = value;
    }
    //debugInit();
    ofs.close();
}

void reLoad(int sig)
{
    (void)sig;
    initDict();
}
void handlerMessage(int sockfd, string ip, uint16_t port, string message)
{
    signal(2, reLoad);
    initDict();
    struct sockaddr_in client;
    bzero(&client, sizeof client);
    client.sin_family = AF_INET;
    client.sin_addr.s_addr = inet_addr(ip.c_str());
    client.sin_port = htons(port);
    auto it = dict.find(message);
    if (it != dict.end())
    {
        sendto(sockfd, it->second.c_str(), it->second.size(), 0, (struct sockaddr *)&client, sizeof(client));
    }
    else
    {
        string message = "unknow";
        sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&client, sizeof(client));
    }
}

// -------------------------demo2:执行命令返回 ->婴儿版xshell --------------------
void execCommond(int sockfd, string ip, uint16_t port, string cmd)
{
    if(cmd.find("rm") != string::npos) 
    {
        cerr << ip << ":" << port << "正在做一个非法的操作" << endl;
        return;
    }

    string response;
    FILE* pf = popen(cmd.c_str(), "r");
    if(pf == nullptr)
    {
        response = cmd + "exec fail";
    }
    else
    {
        char buffer[1024];
        while(fgets(buffer, sizeof buffer, pf))
        {
            response += buffer;
        }
    }

    struct sockaddr_in client;
    bzero(&client, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_addr.s_addr = inet_addr(ip.c_str());
    client.sin_port = htons(port);
    
    sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof(client));

    fclose(pf);

}


// -------------------------demo3:聊天室 --------------------
OnlineUser onlineUser;
void routeMessage(int sockfd, string ip, uint16_t port, string message)
{
    if(message == "online") onlineUser.addUser(ip, port);
    if(message == "offonline") onlineUser.delUser(ip, port);

    sockaddr_in client;
    bzero(&client, sizeof client);
    client.sin_family = AF_INET;
    client.sin_addr.s_addr = inet_addr(ip.c_str());
    client.sin_port = htons(port);

    string response;
    if(onlineUser.isOnline(ip, port))
    {
        //如果在线
        response = message;
        onlineUser.broadCast(sockfd, ip, port, response);
    }
    else
    {
        //不在线，单独给不在线的用户发
        response = "你还没有上线，请先上线，输入online";
        struct sockaddr_in client;
        memset(&client, 0, sizeof(client));
        client.sin_family = AF_INET;
        client.sin_addr.s_addr = inet_addr(ip.c_str());
        client.sin_port = htons(port);
        sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr*)&client, sizeof client);
    }
    
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    // string ip = argv[1];
    // unique_ptr<udpServer> usv(new udpServer(handlerMessage, port));
    // unique_ptr<udpServer> usv(new udpServer(execCommond, port));
    unique_ptr<udpServer> usv(new udpServer(routeMessage, port));

    usv->initServer();
    usv->start();
    return 0;
}